#ifndef __PM_H 
#define __PM_H 

#include <types.h>



#define NR_IDT   256
#define NR_GDT   256

#define DESC_SIZE       0x8

/*   段描述符   */
enum {
    SEG_CODE_SYS = 1,
    SEG_DATA_SYS,
    SEG_DATA_VIDEO,
    SEG_TSS,
    SEG_LDT_TASK,
    SEG_CODE_USER,
    SEG_DATA_USER,
};

#define seg_to_sel(x)    x * DESC_SIZE

/*  RPL特权级 相关   */

#define SA_RPL0			0	    // RPL0
#define SA_RPL1			1	    // RPL1
#define SA_RPL2			2	    // RPL2
#define SA_RPL3			3	    // RPL3

#define SA_TIG			0
#define SA_TIL			4       //代表 LDT 选择子

/*   属性相关   */

#define DA_DR			0x90	// 存在的只读数据段类型值
#define DA_DRW			0x92	// 存在的可读写数据段属性值
#define DA_DRWA			0x93	// 存在的已访问可读写数据段类型值
#define DA_C			0x98	// 存在的只执行代码段属性值

#define DA_CR			0x9a	// 存在的可执行可读代码段属性值
#define DA_CRA			0x9b	// 存在的只执行一致代码段属性值
#define DA_CCO			0x9c	// 存在的只执行一致代码段属性值
#define DA_CCOR			0x9e	// 存在的可执行可读一致代码段属性值

// 系统段描述符类型
#define DA_LDT			  0x82	// 局部描述符表段类型值
#define DA_TaskGate		  0x85	// 任务门类型值
#define DA_386TSS		  0x89	// 可用 386 任务状态段类型值
#define DA_386CGATE		  0x8c	// 386 调用门类型值
#define DA_386IGATE		  0x8e	// 386 中断门类型值
#define DA_386TGATE	      0x8f	// 386 陷阱门类型值
#define DA_DPL0			  0x00	// DPL = 0
#define DA_DPL1			  0x20	// DPL = 1
#define DA_DPL2			  0x40	// DPL = 2
#define DA_DPL3			  0x60	// DPL = 3
#define DPL_MASK          (~(0x60))
#define DA_32			0x4000	// 32 位段  为0则表示 16位段
#define DA_LIMIT_4K		0x8000	// 段界限粒度为 4K 字节
/**
 * @brief seg_desc
 * 段描述符，存储在ldt 和 gdt
 * 段描述符包含:
 *              一致性 代码段/数据段
 *              非一致性 代码段/数据段
 *              LDT 描述符
 *              TSS 描述符
 */
struct seg_desc {
    uint16_t limit_low;
    uint16_t base_low;
    uint8_t base_middle;
    uint8_t access;
    unsigned limit_high: 4;
    unsigned flags: 4;
    uint8_t base_high;
} __attribute__((packed));
/**
 * @brief idt_desc
 * 中断描述符， 存储在 idt
 * 中断描述符包含: 调用门、中断门、陷阱门
 */
struct idt_desc{
    uint16_t base_low;
    uint16_t selector;
    uint8_t always0;
    unsigned gate_type: 4;   
    unsigned flags: 4;  
    uint16_t base_high;
} __attribute__((packed));
/**
 * @brief desc_ptr
 * 描述符指针
 * 描述符指针包含：中断描述符表指针
 *              全局描述符表指针
 */
struct desc_ptr{
    uint16_t limit;
    uint32_t base;
} __attribute__((packed));
/**
 * @brief tss_desc
 * TSS描述符，
 * 通过seg_desc指定TSS的基地址
 * 用于不同特权级栈指针转换
 * ss0  -  esp0
 */
struct tss_desc{
    uint32_t link;
    uint32_t esp0;
    uint32_t ss0;
    uint32_t esp1;
    uint32_t ss1;
    uint32_t esp2;
    uint32_t ss2;
    uint32_t cr3;
    uint32_t eip;
    uint32_t eflags;
    uint32_t eax;
    uint32_t ecx;
    uint32_t edx;
    uint32_t ebx;
    uint32_t esp;
    uint32_t ebp;
    uint32_t esi;
    uint32_t edi;
    uint32_t es;
    uint32_t cs;
    uint32_t ss;
    uint32_t ds;
    uint32_t fs;
    uint32_t gs;
    uint32_t ldtr;
    uint16_t padding1;
    uint16_t iopb_off;
} __attribute__ ((packed));
/**
 * @brief GDT / IDT 初始化
 */
void arch_gdt_init();
void arch_idt_init();

void set_task_ldt(uint32_t base, uint8_t dpl);
struct seg_desc* gdt_base(void);
void idt_install(uint8_t num, uint32_t base, uint16_t selctor, uint8_t attr);

/**
 * @brief 设置IDT中的表项
 */
#define set_int_gate(num, func) \
                    idt_install(num, base, seg_to_sel(SEG_CODE_SYS), DA_386IGATE);
#define set_call_gate(num, base) \
                    idt_install(num, base, seg_to_sel(SEG_CODE_SYS), DA_386CGATE);
#define set_trap_gate(num, base) \
                    idt_install(num, base, seg_to_sel(SEG_CODE_SYS), DA_386TGATE);
#endif
